package mysql

import (
	"context"
	"fmt"
	"go.uber.org/zap"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	gormLogger "gorm.io/gorm/logger"
	"shopping/config"
	"shopping/logger"
	"time"
)

// Db 全局的Db对象
var Db *gorm.DB

// Init 初始化数据库
func Init(cfg *config.MySQLConfig) (err error) {
	// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
	// parseTime=True可以将数据库中的时间类型映射成Go语言中的时间类型  	loc=Local 地区
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.DB)
	Db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
		Logger: loggerCallback{logger.Log},
	})
	if err != nil {
		return err
	}
	// 额外的连接配置
	// 使用sqlDB设置连接池
	sqlDB, err := Db.DB() // database/sql.DB
	if err != nil {
		return err
	}
	// 以下配置要配合 my.conf 进行配置
	// SetMaxIdleConns 设置空闲连接池中连接的最大数量
	sqlDB.SetMaxOpenConns(cfg.MaxIdleConns)
	// SetMaxOpenConns 设置打开数据库连接的最大数量。
	sqlDB.SetMaxOpenConns(cfg.MaxOpenConns)
	// SetConnMaxLifetime 设置了连接可复用的最大时间。
	sqlDB.SetConnMaxLifetime(time.Hour)
	logger.Log.Info("数据库初始化成功")
	return
}

// loggerCallback 实现了 GORM 的回调接口
type loggerCallback struct {
	logger *zap.Logger
}

// LogMode 使用 Zap 打印 SQL 语句
func (l loggerCallback) LogMode(level gormLogger.LogLevel) gormLogger.Interface {
	return l
}

// Info 使用 Zap 打印 SQL 语句
func (l loggerCallback) Info(ctx context.Context, msg string, data ...interface{}) {
	l.logger.Info(fmt.Sprintf(msg, data...))
}

// Warn 使用 Zap 打印 SQL 语句
func (l loggerCallback) Warn(ctx context.Context, msg string, data ...interface{}) {
	l.logger.Warn(fmt.Sprintf(msg, data...))
}

// Error 使用 Zap 打印 SQL 语句
func (l loggerCallback) Error(ctx context.Context, msg string, data ...interface{}) {
	l.logger.Error(fmt.Sprintf(msg, data...))
}

// Trace 使用 Zap 打印 SQL 语句
func (l loggerCallback) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
	if err != nil {
		sql, rows := fc()
		l.logger.Error("gorm trace error", zap.Error(err), zap.String("sql", sql), zap.Int64("rows", rows))
	} else {
		sql, rows := fc()
		l.logger.Debug("gorm trace", zap.String("sql", sql), zap.Int64("rows", rows), zap.Duration("elapsed", time.Since(begin)))
	}
}
